'use strict'

const {DbConnectionService} = require('./dbConnection')

/**
 * 本地配置
 */
class LocalStorageService extends DbConnectionService {
    #dataCache = null

    constructor() {
        const options = {
            dbname: 'local-storage.db'
        }
        super(options)
        this.dbtable = 'config'
    }

    /*
     * 初始化
     */
    init() {
        // 初始化数据库
        this._init()
        // 检查表是否存在
        const masterStmt = this.db.prepare('SELECT * FROM sqlite_master WHERE type=? AND name = ?')
        let tableExists = masterStmt.get('table', this.dbtable)
        if (!tableExists) {
            // 创建表
            const CREATE_TABLE_SQL = `
CREATE TABLE ${this.dbtable} (
 name VARCHAR(50) NOT NULL,
 value text,
 PRIMARY KEY (name)
)`
            this.db.exec(CREATE_TABLE_SQL)
        }
    }

    get db() {
        if (this.conn) {
            return this.conn
        }
        this.init()
        return this.conn
    }

    /*
     * 新增配置
     * ```example
     * addMany([
     *    { name: 'name1', value: 1 },
     *    { name: 'name2', value: 2 },
     *    { name: 'name3', value: 3 },
     * ]);
     * ```
     */
    async addManyAsync(data = []) {
        this.addMany(data)
    }

    addMany(data = []) {
        this.#dataCache = null
        const db = this.db
        const insert = db.prepare(`INSERT INTO ${this.dbtable} (name, value) VALUES (@name, @value)`)
        const insertMany = db.transaction((cats) => {
            for (const cat of cats) insert.run(cat)
        })
        insertMany(data)
    }

    /*
     * 更新配置
    * ```example
     * updateMany([
     *    { name: 'name1', value: 1 },
     *    { name: 'name2', value: 2 },
     *    { name: 'name3', value: 3 },
     * ]);
     * ```
     */
    async updateManyAsync(data = []) {
        this.updateMany(data)
    }

    updateMany(data = []) {
        this.#dataCache = null
        const db = this.db
        const update = db.prepare(`UPDATE ${this.dbtable} SET value = ? WHERE name = ?`)
        const updateMany = db.transaction((cats) => {
            for (const cat of cats) {
                update.run(cat.value, cat.name)
            }
        })
        updateMany(data)
    }

    /**
     * 更新或新增配置
     * ```example
     * batchUpdateOrAdd([
     *    { name: 'name1', value: 1 },
     *    { name: 'name2', value: 2 },
     *    { name: 'name3', value: 3 },
     * ]);
     * ```
     */
    async batchUpdateOrAddAsync(data = []) {
        this.batchUpdateOrAdd(data)
    }

    batchUpdateOrAdd(data = []) {
        this.#dataCache = null
        const db = this.db
        const insert = db.prepare(`INSERT INTO ${this.dbtable} (name, value) VALUES (@name, @value)`)
        const update = db.prepare(`UPDATE ${this.dbtable} SET value = ? WHERE name = ?`)
        const find = db.prepare(`SELECT * FROM ${this.dbtable} WHERE name = ?`)
        const batchUpdateOrAdd = db.transaction((cats) => {
            for (const cat of cats) {
                if (find.get(cat.name)) {
                    update.run(cat.value, cat.name)
                } else {
                    insert.run(cat)
                }
            }
        })
        batchUpdateOrAdd(data)
    }

    /*
     * 查找配置
     */
    findOne(name) {
        const data = this.findAll()
        return {
            name: name,
            value: data[name] !== undefined ? data[name] : null
        }
    }

    /*
     * 获取全部配置
     */
    findAll(name = null) {
        if (this.#dataCache) {
            if (name) {
                return this.#dataCache[name] !== undefined ? {
                    [name]: this.#dataCache[name]
                } : {}
            }
            return this.#dataCache
        }
        let select,
            data = [],
            db = this.db
        select = db.prepare(`SELECT * FROM ${this.dbtable}`)
        data = select.all()
        if (data.length) {
            let result = {}
            for (const item of data) {
                result[item.name] = item.value
            }
            this.#dataCache = result
            if (name) {
                return result[name] !== undefined ? {
                    [name]: result[name]
                } : {}
            }
            return result
        } else {
            return {}
        }
    }
}

LocalStorageService.toString = () => '[class LocalStorageService]'

module.exports = {
    localStorageService: new LocalStorageService()
}
